package com.wang.tool.dagre.node;

import com.wang.tool.dagre.DagreContext;
import com.wang.tool.monitor.LinkLogUtil;
import com.wang.tool.monitor.core.MonitorInfo;
import com.wang.tool.monitor.translator.GlobalErrorTranslator;
import com.wang.tool.common.ErrorInfo;

/**
 * @author shaopeng
 * @date 2022/12/18
 */
public abstract class AbsDagreNode<T> implements DagreNode<T> {

    @Override
    public final Object preCheck(DagreContext<T> context) {
        try {
            return doPreCheck(context);
        } catch (Throwable e) {
            Object result = handleError(context, e);
            ErrorInfo errorInfo = GlobalErrorTranslator.translate(e);
            LinkLogUtil.newTagLog("CatchDagreNodeError")
                    .v1(getId())
                    .v2(errorInfo.getErrorCode())
                    .addAttachment("className", getClass().getSimpleName())
                    .addAttachment(MonitorInfo.ERROR, errorInfo)
                    .log();
            return buildPreResult(result);
        }
    }

    /**
     * 返回预校验结果 无需执行execute
     *
     * @param result 空时返回固定铆定值
     * @return 非空
     */
    protected Object buildPreResult(Object result) {
        return result == null ? DagreNode.NULL_VAL : result;
    }


    @Override
    public final Object execute(DagreContext<T> context) {
        try {
            return doExecute(context);
        } catch (Throwable e) {
            Object result = handleError(context, e);
            ErrorInfo errorInfo = GlobalErrorTranslator.translate(e);
            LinkLogUtil.newTagLog("CatchDagreNodeError")
                    .v1(getId())
                    .v2(errorInfo.getErrorCode())
                    .addAttachment("className", getClass().getSimpleName())
                    .addAttachment(MonitorInfo.ERROR, errorInfo)
                    .log();
            return result;
        }
    }

    /**
     * 预检验
     *
     * @param context 非空
     * @return 返回非空则不对execute进行调度执行
     * @throws Throwable 抛出异常,流程中断
     * @see AbsDagreNode#buildPreResult
     */
    protected abstract Object doPreCheck(DagreContext<T> context) throws Throwable;


    /**
     * 执行业务逻辑
     *
     * @param context 非空
     * @return
     * @throws Throwable 抛出异常,流程中断
     */
    protected abstract Object doExecute(DagreContext<T> context) throws Throwable;

    /**
     * 处理异常场景
     * preCheck/execute出错 都会调用
     *
     * @param context 非空
     * @param e       异常 非空
     * @return 返回值会当做正常结果返回
     * @throws RuntimeException 抛出异常,流程中断
     * @see AbsDagreNode#doExecute
     * @see AbsDagreNode#doPreCheck
     */
    protected abstract Object handleError(DagreContext<T> context, Throwable e);


}
